/*
 * GraphUtils.java
 *
 * This file is part of FUJIWARA.
 * Copyright (C) 2010 Loris Fichera    (loris.fichera@gmail.com)
 *                    Daniele Marletta (danielemar86@gmail.com)
 *
 * FUJIWARA is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * FUJIWARA is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with FUJIWARA.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package graphclient;
import peersim.graph.*;
import java.util.Random;
import java.io.*;
import java.util.Set;
import java.util.HashSet;

/**
 *
 * @author Loris Fichera
 * @author Daniele Marletta
 */

enum GraphType { RANDOM, RANDOMK, BARABASI_ALBERT, WATTS_STROGATZ };

public class GraphUtils {

    private static final String IC = "IC";
    private static String [] colors = {"black","red", "blue", "green", "yellow", "pink",
                                       "purple", "cyan", "orange", "brown", "gray",
                                       "magenta"};


    public static int [] squareMatrixToVector (int [][] matrix) {
        int size = matrix.length;
        int [] vector = new int[size*size];

        int i = 0;
        for (int j = 0; j < size; j ++) {
            for (int k = 0; k < size; k ++) {
                vector[i] = matrix[j][k];
                i++;
            }
        }
        return vector;
    }

    public static int [][] GenerateAdjMatrix (int size, GraphType t ) {

        int [][] adjMatrix = new int[size][size];
        Random r = new Random();
        Graph g = null;

        for (int i = 0; i < size; i ++)
            adjMatrix[i][i] = 0;

        switch (t) {
            case RANDOM:
                for (int i = 0; i < size; i ++) {
                    for (int j = 0; j < size; j ++) {

                        if ( i > j ) {
                            if (r.nextBoolean()) {
                                adjMatrix[i][j] = 1;
                                adjMatrix[j][i] = 1;
                            } else {
                                adjMatrix[i][j] = 0;
                                adjMatrix[j][i] = 0;
                            }
                        }
                    }
                }
                break;

                case RANDOMK:
                g = new BitMatrixGraph(size);
                g = GraphFactory.wireKOut(g, size * 20 / 100, r);

                for (int i = 0; i < size; i ++) {
                    for (int j = 0; j < size; j ++) {
                        if ( i > j ) {
                            if (g.isEdge(i, j)) {
                                adjMatrix[i][j] = 1;
                                adjMatrix[j][i] = 1;
                            }
                        }
                    }
                }
                break;

            case BARABASI_ALBERT:
                g = new BitMatrixGraph(size);
                g = peersim.graph.GraphFactory.wireScaleFreeBA(g, size * 2 / 100, r);

                for (int i = 0; i < size; i ++) {
                    for (int j = 0; j < size; j ++) {
                        if ( i > j ) {
                            if (g.isEdge(i, j)) {
                                adjMatrix[i][j] = 1;
                                adjMatrix[j][i] = 1;
                            }
                        }
                    }
                }
                break;

            case WATTS_STROGATZ:
                g = new BitMatrixGraph(size);
                g = GraphFactory.wireWS(g, size * 4 / 100, 0.1, r);

                for (int i = 0; i < size; i ++) {
                    for (int j = 0; j < size; j ++) {
                        if ( i > j ) {
                            if (g.isEdge(i, j)) {
                                adjMatrix[i][j] = 1;
                                adjMatrix[j][i] = 1;
                            }
                        }
                    }
                }
                break;
        }

        /* Print the adjMatrix
        for (int i = 0; i < size; i ++) {
            for (int j = 0; j < size; j ++)
                System.out.print(adjMatrix[i][j] + " ");
            System.out.println();
        }
        */
        return adjMatrix;
    }

    public static void GenerateNetworkXSource (String source_path,
                                               String img_name,
                                               int [][] adjMatrix,
                                               String [] connectionClass,
                                               String [] classes) {

        Set<String> classesSet = new HashSet<String>();
        for (String c : classes)
            classesSet.add(c);

        if (source_path == null)
            source_path = "./../networkx/source.py";

        if (img_name == null)
            img_name = "graph.png";

        try {

            FileWriter fstream = new FileWriter(source_path);
            BufferedWriter out = new BufferedWriter(fstream);
            
            out.write("#!/usr/bin/env python\n");
            out.write("# -*- coding: utf-8 -*-\n\n");
            out.write("from operator import itemgetter\n");
            out.write("import random\n");
            out.write("import networkx as nx\n");
            out.write("import matplotlib.pyplot as plt\n\n");

            // create graph
            out.write("G = nx.Graph()\n\n");

            // add nodes
            //out.write("for i in range (1," + adjMatrix.length + "):\n");
            for (int i = 0; i < adjMatrix.length; i ++) {
                if (connectionClass[i].equals("IC")) {

                    out.write("G.add_node(" + i + ", "
                            + "Class='"+ classes[i] +"', size='IC')\n");

                } else if (connectionClass[i].equals("MC")) {

                    out.write("G.add_node(" + i + ", "
                            + "Class='"+ classes[i] +"', size='MC')\n");

                } else if (connectionClass[i].equals("C")) {

                    out.write("G.add_node(" + i + ", "
                            + "Class='"+ classes[i] +"', size='C')\n");

                } else if (connectionClass[i].equals("PC")) {

                    out.write("G.add_node(" + i + ", "
                            + "Class='"+ classes[i] +"', size='PC')\n");

                } else if (connectionClass[i].equals("SC")) {

                    out.write("G.add_node(" + i + ", "
                            + "Class='"+ classes[i] +"', size='SC')\n");
                }
            }

            for (int i = 0; i < adjMatrix.length; i++) {
                for (int j = 0; j < adjMatrix[i].length; j++) {
                    if (i > j) {
                        if (adjMatrix[i][j] == 1) {
                            if (classes[i].equals(classes[j])) {

                                out.write ("G.add_edge("
                                           + i + "," + j +", _class='"
                                           + classes[i] +"')\n");

                            } else {

                            out.write ("G.add_edge("
                                       + i + "," + j +", _class = 'none')\n");
                            }
                        }
                    }
                }
            }

            out.write("node_size = [");
            for (int i = 0; i < connectionClass.length; i ++) {
                
                if (connectionClass[i].equals("IC"))
                    out.write("20000, ");

                else if (connectionClass[i].equals("MC"))
                    out.write("3000, ");

                else if (connectionClass[i].equals("C"))
                    out.write("1500, ");

                else if (connectionClass[i].equals("PC"))
                    out.write("1000, ");

                else if (connectionClass[i].equals("SC"))
                    out.write("600, ");
                
            }
            
            out.write("]\n");
            
            out.write("plt.figure(figsize=(50, 50))\n");
            out.write("plt.axis('off')\n");

            //out.write ("colors = ['r', 'b', 'y', 'm', 'c', 'g']\n");
            out.write ("colors = [(random.random(), random.random(), random.random()) for r in range(" + classesSet.size() + ")]\n");
            out.write ("coloured_nodes_list = []\n");
            out.write ("coloured_edges_list = []\n");
            out.write ("edge_color = []\n");

            for (String c : classesSet) {
                out.write("coloured_nodes_list.append"
                        + "([(n,d) for (n,d) in G.nodes(data=True)"
                        + "if d['Class'] is '" + c + "'])\n");
            }

            for (String c : classesSet) {
                out.write("coloured_edges_list.append"
                        + "([(u,v) for (u,v,d) in G.edges(data=True) "
                        + "if d['_class'] is '"+ c +"'])\n");

                out.write("edge_color.append([" + c + ".0]*len(coloured_edges_list[-1]))\n");
            }

            out.write("black_edges_list = [(u,v) for (u,v,d) in G.edges(data=True) if d['_class'] is 'none']\n");
            
            out.write("pos = nx.graphviz_layout(G,prog=\"twopi\", args='-Goverlap=\"scale\"')\n");

            String [] classesArray = classesSet.toArray(new String[0]);
            for (int i = 0; i < classesArray.length; i++) {
                out.write("c = [colors[" + i + "]]*len(coloured_edges_list["+ i +"])\n");
                out.write("nx.draw_networkx_edges(G, pos, edgelist=coloured_edges_list["+ i +"], edge_color=c)\n");

                
                out.write("node_according_to_size = [n for (n,d) in coloured_nodes_list["+ i +"] if d['size'] is 'IC']\n");
                out.write("n = [colors[" + i + "]]*len(node_according_to_size)\n");
                out.write("nx.draw_networkx_nodes(G, pos, nodelist=node_according_to_size, node_size=15000, node_color = n)\n");

                out.write("node_according_to_size = [n for (n,d) in coloured_nodes_list["+ i +"] if d['size'] is 'MC']\n");
                out.write("n = [colors[" + i + "]]*len(node_according_to_size)\n");
                out.write("nx.draw_networkx_nodes(G, pos, nodelist=node_according_to_size, node_size=3000, node_color = n)\n");

                out.write("node_according_to_size = [n for (n,d) in coloured_nodes_list["+ i +"] if d['size'] is 'C']\n");
                out.write("n = [colors[" + i + "]]*len(node_according_to_size)\n");
                out.write("nx.draw_networkx_nodes(G, pos, nodelist=node_according_to_size, node_size=1500, node_color = n)\n");

                out.write("node_according_to_size = [n for (n,d) in coloured_nodes_list["+ i +"] if d['size'] is 'PC']\n");
                out.write("n = [colors[" + i + "]]*len(node_according_to_size)\n");
                out.write("nx.draw_networkx_nodes(G, pos, nodelist=node_according_to_size, node_size=1000, node_color = n)\n");

                out.write("node_according_to_size = [n for (n,d) in coloured_nodes_list["+ i +"] if d['size'] is 'SC']\n");
                out.write("n = [colors[" + i + "]]*len(node_according_to_size)\n");
                out.write("nx.draw_networkx_nodes(G, pos, nodelist=node_according_to_size, node_size=700, node_color = n)\n");
            }

            out.write("nx.draw_networkx_edges(G, pos, edgelist=black_edges_list, alpha =0.5, edge_color='black')\n");


            out.write("nx.draw_networkx_labels(G, pos, font_size=20, "
                    + "font_family='sans-serif', "
                    + "font_color = 'white')\n");
            
            out.write("plt.savefig(\"" + img_name + "\")\n");

            out.flush();
            
        } catch (Exception e) {

            System.out.println("Error in writing file.");

        }
    }

    public static void GenerateDotSource (String path, int [][] adjMatrix,String[] connectionVector,String [] classes) {

        try {

            if (path == null)
                path = "output.dot";

            FileWriter fstream = new FileWriter(path);
            BufferedWriter out = new BufferedWriter(fstream);
            out.write("graph basicNet \n {");
            out.write("// General edge properties \n\tedge [len=2]; \n");
            out.write("\n");
            int colorCounter = 0;

            for (int c = 0; c < classes.length; c++)
            {
               /* if (classes[c].equals("0"))
                {
                   //System.out.println("Got IC");
                   out.write("\tV"+c+ "[label=\"IC\",shape=box,color="+ colors[colorCounter] + "]; \n");
                   colorCounter++;

                } else {
                  out.write("\tV"+c+ "[label=" + classes[c] + "]; \n");

                }*/
                int color = Integer.parseInt(classes[c]);
                if (connectionVector[c].equals(IC)) {
                    out.write("\tV"+c+ "[label=IC" + classes[c] + ",shape=box,color="+ colors[color] + "]; \n");
                } else {
                out.write("\tV"+c+ "[label=" + classes[c] + ",color="+ colors[color] + "]; \n");
                }
            }

            out.write("\n");
            for (int i = 0; i < adjMatrix.length; i ++) {
                for (int j = 0; j < adjMatrix.length; j++) {
                    if (i < j) {
                        if ( adjMatrix[i][j] == 1){
                            out.write("\tV" + i + " -- " +
                                      "V" + j + ";\n");
                        }
                    }
                }
            }

            out.write("} //End of graph");
            out.flush();

        } catch (Exception e) {

            System.out.println(e);
            System.out.println(e.getCause());
            e.printStackTrace();

        }
    }

}
